package service

// #include <stdlib.h>
//#include <stdint.h>
/*
typedef char* (*CallbackFunction)(char* action, char* function, char* param);
char* CallbackAgent(CallbackFunction invokeFunc, char* action, char* function, char* param)
{
    return invokeFunc(action, function, param);
}
typedef void (*ReleaseCallbackReturnFunction)(char* callbackReturnString);
void ReleaseCallbackReturnAgent(ReleaseCallbackReturnFunction releaseFunc, char* callbackReturnString)
{
	  releaseFunc(callbackReturnString);
}

typedef struct _Cosmos_RoleResponsibility
{
    CallbackFunction Callback;

	ReleaseCallbackReturnFunction ReleaseCallback;
} Cosmos_RoleResponsibility;
Cosmos_RoleResponsibility* GetCosmos_RoleResponsibility(void *pointer)
{
	return (Cosmos_RoleResponsibility*)pointer;
}

typedef struct _Cosmos_EnvironmentEventArgs
{
    char* EventName;
    char* EventContext;
} Cosmos_EnvironmentEventArgs;
typedef void (*Cosmos_EnvironmentEventHandler)(Cosmos_EnvironmentEventArgs* environmentEventArgs);
void CallCosmos_EnvironmentEventHandler(Cosmos_EnvironmentEventHandler handler, Cosmos_EnvironmentEventArgs* environmentEventArgs)
{
    handler(environmentEventArgs);
}

typedef void* Cosmos_Handle;
typedef struct _CosmosResult
{
	int64_t Code;
	char* Message;
} Cosmos_Result;
typedef struct _Cosmos_CallContext
{
	Cosmos_Handle CallerHandle;
	Cosmos_Handle TargetHandle;
} Cosmos_CallContext;
typedef struct _Cosmos_DataFrame
{
	char* Data;
	int32_t DataSize;
} Cosmos_DataFrame;
typedef struct _Cosmos_NotifyRequest
{
	char* Topic;
	char* RoutingKey;
	char* Message;
} Cosmos_NotifyRequest;
typedef struct _Cosmos_InvokeRequest
{
	char* Method;
	char* Parameters;
} Cosmos_InvokeRequest;
typedef struct _Cosmos_InvokeResponse
{
	Cosmos_Result* Result;
	Cosmos_DataFrame* DataFrame;
} Cosmos_InvokeResponse;
typedef struct _Cosmos_SubscriptionDataFrame
{
	char* SubscriptionId;
	Cosmos_DataFrame* DataFrame;
} Cosmos_SubscriptionDataFrame;
typedef struct _Cosmos_SubscribeRequest
{
	char* Topic;
	char* Parameters;
} Cosmos_SubscribeRequest;
typedef struct _CosmosSubscription
{
	char* SubscriptionId;
} Cosmos_Subscription;
typedef struct _Cosmos_SubscribeResponse
{
	Cosmos_Result* Result;
	Cosmos_Subscription* Subscription;
} Cosmos_SubscribeResponse;
typedef Cosmos_Result* (*Cosmos_NotifyDelegate)(Cosmos_CallContext* actionContext, Cosmos_NotifyRequest* notifyRequest);
typedef Cosmos_InvokeResponse* (*Cosmos_InvokeDelegate)(Cosmos_CallContext* actionContext, Cosmos_InvokeRequest* invokeRequest);
typedef void (*Cosmos_ReleaseInvokeResponseDelegate)(Cosmos_CallContext* actionContext, Cosmos_InvokeResponse* invokeResponse);
typedef Cosmos_SubscribeResponse* (*Cosmos_SubscribeDelegate)(Cosmos_CallContext* actionContext, Cosmos_SubscribeRequest* subscribeRequest);
typedef void (*Cosmos_ReleaseSubscribeResponseDelegate)(Cosmos_CallContext* actionContext, Cosmos_SubscribeResponse* subscriptionResponse);
typedef Cosmos_Result* (*Cosmos_PushSubscriptionDataDelegate) (Cosmos_CallContext* actionContext, Cosmos_SubscriptionDataFrame* subscriptionDataFrame);
typedef Cosmos_Result* (*Cosmos_UnsubscribeDelegate) (Cosmos_CallContext* actionContext, Cosmos_Subscription* subscription);
typedef void (*Cosmos_ReleaseResultDelegate) (Cosmos_CallContext* actionContext, Cosmos_Result* result);
typedef struct _Cosmos_Responsibility
{
	Cosmos_NotifyDelegate Cosmos_NotifyHandler;
	Cosmos_InvokeDelegate Cosmos_InvokeHandler;
	Cosmos_ReleaseInvokeResponseDelegate Cosmos_ReleaseInvokeResponseHandler;
	Cosmos_SubscribeDelegate Cosmos_SubscribeHandler;
	Cosmos_ReleaseSubscribeResponseDelegate Cosmos_ReleaseSubscribeResponseHandler;
	Cosmos_PushSubscriptionDataDelegate Cosmos_PushSubscriptionDataHandler;
	Cosmos_UnsubscribeDelegate Cosmos_UnsubscribeHandler;
	Cosmos_ReleaseResultDelegate Cosmos_ReleaseResultHandler;
} Cosmos_Responsibility;


Cosmos_Responsibility* GetCosmos_Responsibility(void *pointer)
{
	return (Cosmos_Responsibility*)pointer;
}
Cosmos_Result* CallCosmos_NotifyDelegate(Cosmos_NotifyDelegate handler, Cosmos_CallContext* actionContext, Cosmos_NotifyRequest* notifyRequest)
{
    return handler(actionContext, notifyRequest);
}
void ReleaseCosmos_CallContext(Cosmos_CallContext* context)
{
    if (context == NULL) {
        return;
    }
	free(context);
    return;
}
void ReleaseCosmos_NotifyRequest(Cosmos_NotifyRequest* request)
{
    if (request == NULL) {
        return;
    }
    if (request->Topic != NULL) {
        free(request->Topic);
    }
    if (request->Message != NULL) {
        free(request->Message);
    }
    if (request->RoutingKey != NULL) {
        free(request->RoutingKey);
    }
	free(request);
    return;
}
int32_t CheckNotifyHandler(Cosmos_NotifyDelegate handler)
{
    if (handler == NULL)
    {
        return -1;
    }
    return 1;
}
int32_t CheckCosmosResult(Cosmos_Result* result)
{
    if (result == NULL)
    {
        return -1;
    }
    return 1;
}



Cosmos_InvokeResponse* CallCosmos_InvokeDelegate(Cosmos_InvokeDelegate handler, Cosmos_CallContext* actionContext, Cosmos_InvokeRequest* request)
{
	return handler(actionContext, request);
}
void ReleaseCosmos_InvokeRequest(Cosmos_InvokeRequest* request)
{
	if (request == NULL) {
		return;
	}
	if (request->Method != NULL) {
		free(request->Method);
	}
	if (request->Parameters != NULL) {
		free(request->Parameters);
	}
	free(request);
	return;
}
void CallCosmos_ReleaseInvokeResponseDelegate(Cosmos_ReleaseInvokeResponseDelegate handler, Cosmos_CallContext* actionContext, Cosmos_InvokeResponse* response)
{
	return handler(actionContext, response);
}
int32_t CheckInvokeHandler(Cosmos_InvokeDelegate handler)
{
    if (handler == NULL)
    {
        return -1;
    }
    return 1;
}
int32_t CheckInvokeResponse(Cosmos_InvokeResponse* response)
{
    if (response == NULL)
    {
        return -1;
    }
	if (response->Result == NULL)
    {
        return -2;
    }
    return 1;
}


Cosmos_SubscribeResponse* CallCosmos_SubscribeDelegate(Cosmos_SubscribeDelegate handler, Cosmos_CallContext* actionContext, Cosmos_SubscribeRequest* request)
{
	return handler(actionContext, request);
}
void ReleaseCosmos_SubscribeRequest(Cosmos_SubscribeRequest* request)
{
	if (request == NULL) {
		return;
	}
	if (request->Topic != NULL) {
		free(request->Topic);
	}
	if (request->Parameters != NULL) {
		free(request->Parameters);
	}
	free(request);
	return;
}
void CallCosmos_ReleaseSubscribeResponseDelegate(Cosmos_ReleaseSubscribeResponseDelegate handler, Cosmos_CallContext* actionContext, Cosmos_SubscribeResponse* response)
{
	return handler(actionContext, response);
}
int32_t CheckSubscribeHandler(Cosmos_SubscribeDelegate handler)
{
    if (handler == NULL)
    {
        return -1;
    }
    return 1;
}
int32_t CheckSubscribeResponse(Cosmos_SubscribeResponse* response)
{
    if (response == NULL)
    {
        return -1;
    }
	if (response->Result == NULL)
    {
        return -2;
    }
    return 1;
}

void CallCosmos_ReleaseResultDelegate(Cosmos_ReleaseResultDelegate handler, Cosmos_CallContext* actionContext, Cosmos_Result* response)
{
	return handler(actionContext, response);
}

void CallCosmos_ReleaseResult(void* pointer)
{
	Cosmos_Result* result = (Cosmos_Result*)pointer;
	if (result == NULL)
	{
		return;
	}

	if (result->Message != NULL)
	{
		free(result->Message);
	}
	free(result);
	return;
}
void CallCosmos_ReleaseDataFrame(void* pointer)
{
	Cosmos_DataFrame* data = (Cosmos_DataFrame*)pointer;
	if (data == NULL)
	{
		return;
	}

	if (data->Data != NULL)
	{
		free(data->Data);
	}
	free(data);
	return;
}
void CallCosmos_ReleaseInvokeResponse(void* pointer)
{
	Cosmos_InvokeResponse* response = (Cosmos_InvokeResponse*)pointer;
	if (response == NULL)
	{
		return;
	}

	if (response->Result != NULL)
	{
		CallCosmos_ReleaseResult(response->Result);
	}
	if (response->DataFrame != NULL)
	{
		CallCosmos_ReleaseDataFrame(response->DataFrame);
	}
	free(response);
	return;
}
int32_t IsStringNull(void *str)
{
    if (str == NULL)
    {
        return -1;
    }
    return 1;
}

char* ConvertString(void *str)
{
    return (char*)str;
}
*/
import "C"
import (
	"context"
	"encoding/json"
	"unsafe"

	biz "Cosmos.Communication/internal/biz"
	"Cosmos.Communication/internal/data"
	"github.com/go-kratos/kratos/v2/log"
)

type Responsibility interface {
	biz.DataSet
	biz.Invoke
	biz.Notify
	biz.Health
}

func NewResponsibility(data *data.Data, logger log.Logger) (a Responsibility, cf func(), ex error) {
	a = &responsibility{data, log.NewHelper(logger)}
	cf = a.Close
	ex = nil
	return
}

type responsibility struct {
	infrastructure *data.Data
	logHelper      *log.Helper
}

func (d *responsibility) info(a ...interface{}) {
	if d.logHelper == nil {
		return
	}
	data, err := json.Marshal(a)
	if err != nil {
		d.logHelper.Info("Info Marshal Error:", err)
		return
	}
	d.logHelper.Info(string(data))
}

func (d *responsibility) Query(ctx context.Context, request *biz.DataQueryRequest) (result *biz.Result[*biz.DataQueryResponse], err error) {
	result = &biz.Result[*biz.DataQueryResponse]{
		Code: 200,
	}
	return
}
func (d *responsibility) Subscribe(ctx context.Context, request *biz.DataSubscribeRequest) (result *biz.Result[*biz.DataSubscribeResponse], err error) {
	result = &biz.Result[*biz.DataSubscribeResponse]{
		Code: 200,
		Data: &biz.DataSubscribeResponse{},
	}

	if request == nil {
		result.Code = 400
		result.Message = "Subscribe request is nil"
		return
	}
	if cosmos_responsibility == nil || cosmos_responsibility.Cosmos_SubscribeHandler == nil || C.CheckSubscribeHandler(cosmos_responsibility.Cosmos_SubscribeHandler) != 1 {
		result.Code = 500
		result.Message = "cosmos_responsibility is nil"
		return
	}

	var cosmos_callcontext = (*C.Cosmos_CallContext)(C.malloc(C.sizeof_Cosmos_CallContext))
	var cosmos_request = (*C.Cosmos_SubscribeRequest)(C.malloc(C.sizeof_Cosmos_SubscribeRequest))
	cosmos_request.Topic = C.CString(request.Type)
	cosmos_request.Parameters = C.CString(request.Parameters)
	var cosmos_response = C.CallCosmos_SubscribeDelegate(cosmos_responsibility.Cosmos_SubscribeHandler, cosmos_callcontext, cosmos_request)
	if cosmos_response == nil || cosmos_response.Result == nil || C.CheckSubscribeResponse(cosmos_response) != 1 {
		result.Code = 500
		result.Message = "cosmos_response or cosmos_response.result is nil"
	} else {
		result.Code = int(cosmos_response.Result.Code)
		if cosmos_response.Result.Message != nil {
			result.Message = C.GoString(cosmos_response.Result.Message)
		}
	}
	if result.Code == 200 {
		if cosmos_response.Subscription != nil && cosmos_response.Subscription.SubscriptionId != nil {
			result.Data.Id = C.GoString(cosmos_response.Subscription.SubscriptionId)
		}
	}

	if cosmos_responsibility.Cosmos_ReleaseSubscribeResponseHandler != nil {
		d.info("Start CallCosmos_ReleaseSubscribeResponseDelegate")
		C.CallCosmos_ReleaseSubscribeResponseDelegate(cosmos_responsibility.Cosmos_ReleaseSubscribeResponseHandler, cosmos_callcontext, cosmos_response)
		d.info("End CallCosmos_ReleaseSubscribeResponseDelegate")
	}

	C.ReleaseCosmos_CallContext(cosmos_callcontext)
	C.ReleaseCosmos_SubscribeRequest(cosmos_request)
	return
}
func (d *responsibility) Unsubscribe(ctx context.Context, request *biz.DataUnsubscribeRequest) (result *biz.Result[*biz.DataUnsubscribeResponse], err error) {
	result = &biz.Result[*biz.DataUnsubscribeResponse]{
		Code: 200,
	}
	return
}
func (d *responsibility) Push(ctx context.Context, data *biz.DataFrame) (err error) {
	return nil
}
func (d *responsibility) Close() {
}

func (d *responsibility) Poll() *biz.DataFrame {
	return d.infrastructure.PollDataFrame()
}

func (d *responsibility) Invoke(ctx context.Context, request *biz.InvokeRequest) (result *biz.Result[*biz.InvokeResponse], err error) {
	result = &biz.Result[*biz.InvokeResponse]{
		Code: 200,
		Data: &biz.InvokeResponse{},
	}

	if request == nil {
		result.Code = 400
		result.Message = "invoke request is nil"
		return
	}
	if cosmos_responsibility == nil || cosmos_responsibility.Cosmos_InvokeHandler == nil || C.CheckInvokeHandler(cosmos_responsibility.Cosmos_InvokeHandler) != 1 {
		result.Code = 500
		result.Message = "Cosmos_InvokeHandler is nil"
		return
	}

	var cosmos_callcontext = (*C.Cosmos_CallContext)(C.malloc(C.sizeof_Cosmos_CallContext))
	var cosmos_invokerequest = (*C.Cosmos_InvokeRequest)(C.malloc(C.sizeof_Cosmos_InvokeRequest))
	cosmos_invokerequest.Method = C.CString(request.Function)
	cosmos_invokerequest.Parameters = C.CString(request.Parameters)
	var cosmos_invokeresponse = C.CallCosmos_InvokeDelegate(cosmos_responsibility.Cosmos_InvokeHandler, cosmos_callcontext, cosmos_invokerequest)
	if cosmos_invokeresponse == nil || cosmos_invokeresponse.Result == nil || C.CheckInvokeResponse(cosmos_invokeresponse) != 1 {
		result.Code = 500
		result.Message = "cosmos_invokeresponse is nil"
	} else {
		result.Code = int(cosmos_invokeresponse.Result.Code)
		if cosmos_invokeresponse.Result.Message != nil {
			result.Message = C.GoString(cosmos_invokeresponse.Result.Message)
		}

	}
	if result.Code == 200 {
		if cosmos_invokeresponse.DataFrame != nil && cosmos_invokeresponse.DataFrame.Data != nil {
			result.Data.Value = C.GoString(cosmos_invokeresponse.DataFrame.Data)
		}
	}

	if cosmos_responsibility.Cosmos_ReleaseInvokeResponseHandler != nil {
		d.info("Start CallCosmos_ReleaseInvokeResponseDelegate")
		C.CallCosmos_ReleaseInvokeResponseDelegate(cosmos_responsibility.Cosmos_ReleaseInvokeResponseHandler, cosmos_callcontext, cosmos_invokeresponse)
		d.info("end CallCosmos_ReleaseInvokeResponseDelegate")
	}

	C.ReleaseCosmos_CallContext(cosmos_callcontext)
	C.ReleaseCosmos_InvokeRequest(cosmos_invokerequest)
	return
}

func (d *responsibility) Notify(ctx context.Context, request *biz.NotifyRequest) (result *biz.Result[*biz.NotifyResponse], err error) {
	result = &biz.Result[*biz.NotifyResponse]{
		Code: 200,
	}

	if request == nil {
		result.Code = 400
		result.Message = "notify request is nil"
		return
	}
	if cosmos_responsibility == nil || cosmos_responsibility.Cosmos_NotifyHandler == nil || C.CheckNotifyHandler(cosmos_responsibility.Cosmos_NotifyHandler) != 1 {
		result.Code = 500
		result.Message = "cosmos_notifyhandler is nil"
		return
	}

	d.info("Start callCosmos_NotifyDelegate")
	var cosmos_callcontext = (*C.Cosmos_CallContext)(C.malloc(C.sizeof_Cosmos_CallContext))
	var cosmos_notifyrequest = (*C.Cosmos_NotifyRequest)(C.malloc(C.sizeof_Cosmos_NotifyRequest))
	cosmos_notifyrequest.Topic = C.CString(request.Topic)
	cosmos_notifyrequest.Message = C.CString(request.Message)
	cosmos_notifyrequest.RoutingKey = C.CString(request.RoutingKey)
	var cosmos_result = C.CallCosmos_NotifyDelegate(cosmos_responsibility.Cosmos_NotifyHandler, cosmos_callcontext, cosmos_notifyrequest)
	if cosmos_result == nil || C.CheckCosmosResult(cosmos_result) != 1 {
		d.info("callCosmos_NotifyDelegate failed", "cosmos_result is nil")
	} else {
		d.info("callCosmos_NotifyDelegate result:", int(cosmos_result.Code))
	}

	if cosmos_responsibility.Cosmos_ReleaseResultHandler != nil {
		d.info("Start CallCosmos_ReleaseResultDelegate")
		C.CallCosmos_ReleaseResultDelegate(cosmos_responsibility.Cosmos_ReleaseResultHandler, cosmos_callcontext, cosmos_result)
		d.info("End CallCosmos_ReleaseResultDelegate")
	}

	C.ReleaseCosmos_CallContext(cosmos_callcontext)
	d.info("callCosmos_NotifyDelegate", "ReleaseCosmos_CallContext")
	C.ReleaseCosmos_NotifyRequest(cosmos_notifyrequest)
	d.info("callCosmos_NotifyDelegate", "ReleaseCosmos_NotifyRequest")
	return
}

func (d *responsibility) Check(ctx context.Context, request *biz.HealthCheckRequest) (result *biz.Result[*biz.HealthCheckResponse], err error) {
	result = &biz.Result[*biz.HealthCheckResponse]{
		Code: 200,
	}
	return
}

// #region pointer
var (
	callbackFunc                   C.CallbackFunction
	releaseFunc                    C.ReleaseCallbackReturnFunction
	cosmos_environmentEventHandler C.Cosmos_EnvironmentEventHandler
	cosmos_responsibility          *C.Cosmos_Responsibility
)

func RegisterResponsibility(responsibilityPointer unsafe.Pointer) {
	if responsibilityPointer == nil {
		return
	}

	cosmos_responsibility = C.GetCosmos_Responsibility(responsibilityPointer)
	log.Info("保存大核回调指针:", responsibilityPointer,
		unsafe.Pointer(cosmos_responsibility.Cosmos_InvokeHandler),
		unsafe.Pointer(cosmos_responsibility.Cosmos_NotifyHandler),
		unsafe.Pointer(cosmos_responsibility.Cosmos_PushSubscriptionDataHandler),
		unsafe.Pointer(cosmos_responsibility.Cosmos_ReleaseInvokeResponseHandler),
		unsafe.Pointer(cosmos_responsibility.Cosmos_ReleaseResultHandler),
		unsafe.Pointer(cosmos_responsibility.Cosmos_ReleaseSubscribeResponseHandler),
		unsafe.Pointer(cosmos_responsibility.Cosmos_SubscribeHandler),
		unsafe.Pointer(cosmos_responsibility.Cosmos_UnsubscribeHandler))
}

func RegisterEnvironmentEventHandler(eventHandler unsafe.Pointer) {
	if eventHandler == nil {
		return
	}
	cosmos_environmentEventHandler = (C.Cosmos_EnvironmentEventHandler)(eventHandler)
}

func CallCosmos_ReleaseResultAgent(result unsafe.Pointer) {
	C.CallCosmos_ReleaseResult(result)
}

func CallCosmos_ReleaseInvokeResponseAgent(invokeResponse unsafe.Pointer) {
	C.CallCosmos_ReleaseInvokeResponse(invokeResponse)
}

func CallCosmos_ReleaseDataFrameAgent(dataFrame unsafe.Pointer) {
	C.CallCosmos_ReleaseDataFrame(dataFrame)
}

func Call_ConvertString(str unsafe.Pointer) (res string) {
	if C.IsStringNull(str) != 1 {
		return ""
	}

	return C.GoString(C.ConvertString(str))
}

//#endregion
